package info.empathymobile.forecastmethods;


public class HoltWintersExpSmooth implements ForecastMethod {

	public static final String NAME = "Holt-Winters Exponential Smoothing";
	public static final int VERSION = 3;

	@Override
	public String getName() {
		return NAME;
	}
	@Override
	public int getVersion() {
		return VERSION;
	}

	@Override
	public int[] doForecasting(int[] Y, int h) {
		int m = 7;
		double alpha = 0.0; 
		double beta = 0.0;
		double gamma = 0.4;
        int seasons = Y.length / m;
        
        double[] L = new double[Y.length]; 
        double[] T = new double[Y.length]; 
        double[] S = new double[Y.length];
        int[] F = new int[Y.length + h];
        
        //initial L
        L[0] = Y[0];

        //Initial T
        double sum = 0;
        for (int t = 0; t < m; t++) {
            sum += (Y[m + t] - Y[t]);
        }
        T[0] = sum / (m * m);
        
        //Initial Seasonal Indexes
        double[] seasonalAverage = new double[seasons];
        double[] averagedObservations = new double[Y.length];

        for (int i = 0; i < seasons; i++) {
            for (int j = 0; j < m; j++) {
                seasonalAverage[i] += Y[(i * m) + j];
            }
            seasonalAverage[i] /= m;
        }

        for (int i = 0; i < seasons; i++) {
            for (int j = 0; j < m; j++) {
                averagedObservations[(i * m) + j] = Y[(i * m) + j] / seasonalAverage[i];
            }
        }

        for (int t = 0; t < m; t++) {
            for (int i = 0; i < seasons; i++) {
                S[t] += averagedObservations[(i * m) + t];
            }
            S[t] /= seasons;
        }
        
        //FORECAST
        for (int t = 1; t < Y.length; t++) {
            // Calculate level smoothing
            if ((t - m) >= 0) {
                L[t] = alpha * (Y[t] / S[t - m]) + (1.0 - alpha) * (L[t - 1] + T[t - 1]);
            } 
            else {
                L[t] = alpha * Y[t] + (1.0 - alpha) * (L[t - 1] + T[t - 1]);
            }

            // Calculate trend smoothing
            T[t] = beta * (L[t] - L[t - 1]) + (1 - beta) * T[t - 1];

            // Calculate seasonal smoothing
            if ((t - m) >= 0) {
                S[t] = gamma * (Y[t] / (L[t - 1] + T[t - 1])) + (1.0 - gamma) * S[t - m];
            }

            // Calculate forecast
            if ((t + (((h-1) % m)+1)) >= m) {
                F[t + h] = (int) ((L[t] + (h * T[t])) * S[t - m + ((h-1) % m)+1]);
            }
        }
        
        return F;
	}
}
